1주차 과제#2
Conversation
There was a problem hiding this comment.
Pull request overview
Week01 과제로 Bun + React 환경을 구성하고, Todo 예제를 통해 컴포넌트 설계 패턴(모놀리식 → P/C → 커스텀 훅 → 컴파운드 컴포넌트)을 단계별로 실습할 수 있도록 구성한 PR입니다.
Changes:
- Bun(serve/build) 기반의 React + Tailwind 실행/빌드 환경 추가
- Todo 예제 Step1~Step4 및 실습용(MyPractice) 화면/컴포넌트 추가
- Step 선택 탭(App) 및 프론트엔드 엔트리포인트 구성
Reviewed changes
Copilot reviewed 16 out of 19 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| week01/tsconfig.json | React/번들러 모드 중심 TS 설정 추가 |
| week01/package.json | Bun + React + Tailwind 의존성/스크립트 추가 |
| week01/bunfig.toml | static serve 플러그인(tailwind) 설정 추가 |
| week01/bun.lock | 의존성 잠금 파일 추가 |
| week01/bun-env.d.ts | SVG/CSS 모듈 타입 선언 추가 |
| week01/build.ts | Bun 빌드 스크립트 추가 |
| week01/src/index.ts | Bun 서버 라우팅/개발 옵션(HMR 등) 추가 |
| week01/src/index.html | HTML 엔트리(React 로드) 추가 |
| week01/src/frontend.tsx | React DOM 마운트 엔트리 추가 |
| week01/src/index.css | Tailwind 기반 전역 스타일 추가 |
| week01/src/logo.svg | 로고 에셋 추가 |
| week01/src/App.tsx | Step 탭 UI 및 각 Step 컴포넌트 라우팅 추가 |
| week01/src/todo/Step1_Monolithic.tsx | Step1 모놀리식 Todo 예제 추가 |
| week01/src/todo/Step2_PresentationalContainer.tsx | Step2 P/C 패턴 예제 추가 |
| week01/src/todo/Step3_CustomHook.tsx | Step3 커스텀 훅 패턴 예제 추가 |
| week01/src/todo/Step4_CompoundComponent.tsx | Step4 컴파운드 컴포넌트 패턴 예제 추가 |
| week01/src/practice/MyPractice.tsx | 실습용 컴파운드 컴포넌트 예제 추가 |
| week01/CLAUDE.md | week01에서 Bun 우선 사용 가이드 추가 |
| week01/.gitignore | week01 전용 ignore 규칙 추가 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| TodoList.Header = function Header({ title }: { title: string }) { | ||
| const { todos } = useTodoContext(); | ||
| const done = todos.filter((t) => t.completed).length; |
There was a problem hiding this comment.
TodoList.Header/.AddForm/.Items/.Item/.Empty를 function TodoList에 직접 할당하고 있는데, TypeScript에서는 함수 타입에 이런 정적 프로퍼티가 선언되어 있지 않아서 Property 'Header' does not exist on type ... 형태의 컴파일 에러가 납니다. TodoList를 TodoListComponent(호출 시그니처 + 서브컴포넌트 프로퍼티)로 타입 선언하거나 Object.assign/namespace merging 패턴으로 정적으로 구성해 타입을 맞춰주세요.
| </span> | ||
| <button | ||
| onClick={() => onDelete(todo.id)} | ||
| className="text-white/30 hover:text-red-400 transition-colors text-lg leading-none" |
There was a problem hiding this comment.
TodoList.Item의 삭제 버튼이 아이콘(×)만 제공되어 접근성 레이블이 없습니다. aria-label 또는 sr-only 텍스트를 추가해 주세요.
| className="text-white/30 hover:text-red-400 transition-colors text-lg leading-none" | |
| className="text-white/30 hover:text-red-400 transition-colors text-lg leading-none" | |
| aria-label={`"${todo.text}" 삭제`} |
| TodoList.Header = function Header({ title }: { title: string }) { | ||
| const { todos } = useTodoContext(); | ||
| const done = todos.filter((t) => t.completed).length; | ||
|
|
||
| return ( | ||
| <div className="flex items-center justify-between"> | ||
| <h2 className="text-xl font-bold">{title}</h2> | ||
| <span className="text-sm text-white/40"> | ||
| {done} / {todos.length} 완료 | ||
| </span> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| TodoList.AddForm = function AddForm() { | ||
| const { input, setInput, addTodo } = useTodoContext(); | ||
|
|
There was a problem hiding this comment.
여기서도 TodoList.Header/.AddForm/.Items/.Item/.Empty를 function TodoList에 직접 할당하고 있는데, TypeScript에서 TodoList 함수 타입에 해당 정적 프로퍼티가 선언되지 않아 컴파일 에러가 발생합니다. TodoList를 (컴포넌트 호출 시그니처 + 서브컴포넌트) 교차 타입으로 선언하거나 Object.assign/namespace merging으로 구성해 타입을 명시해 주세요.
| import { App } from "./App"; | ||
|
|
||
| function start() { | ||
| const root = createRoot(document.getElementById("root")!); |
There was a problem hiding this comment.
document.getElementById("root")!는 DOM 구조가 바뀌거나 스크립트가 다른 페이지에서 재사용될 때 런타임에서 바로 크래시 납니다. root가 없을 경우 명확한 에러를 던지거나 조용히 리턴하는 등 안전장치를 추가해 주세요.
| const root = createRoot(document.getElementById("root")!); | |
| const container = document.getElementById("root"); | |
| if (!container) { | |
| console.error('Root element with id "root" not found. React app will not start.'); | |
| return; | |
| } | |
| const root = createRoot(container); |
No description provided.